LES DIFFERENTS TYPES D'APPELS ENTRE
LA SECTION CODE ET LES FONCTIONS



L'IAT n'est pas une fin en soit. Il contient les noms des DLL et de leurs fonctions. Mais il faut bien que le programme consulte cette liste à un moment donné, et c'est dans la section .code que ça se passe. Quand vous utilisez une API dans votre code, ce code fait une liaison vers l'IAT pour accéder à cette fonction. Et forcément ce serait trop simple semble-t-il qu'il n'existe qu'un seul type de lien entre le code et l'IAT. Ce tutorial fait la lumière sur ce point.

Toutes les informations qui suivent sont le résultat d'observations. Il se peut donc que d'autres types de liens existent et ne soient pas décrits ici. Cependant je pense quand mêmes que la totalité des cas (Normaux) soient décrit ici, même si je ne peux pas le garantir à 100%. Je précise bien cas normaux parce qu'il est possible d'inventer de nouveaux types de liens, je pense en particulier à la façon dont Aspack crée des liens atypiques en évitant de pointer directement sur le début de l'adresse de la fonction qu'elle appelle.




Je pense qu'il exite quatre principaux types de liens:



I) APPEL DIRECT PROCHE

Call A1
A1 jmp dword ptr [IAT]

II) APPEL DIRECT LOINTAIN

Call dword ptr [adresseIAT]
III) APPEL INDIRECT

Call dword ptr [adresse???]
IV) APPEL INDIRECT RETARDÉ

Mov esi, dword ptr [adresse???]
Call esi






I) APPEL DIRECT PROCHE :

Je lui donne le nom d' "Appel Direct Proche " car pour appeler la fonction un simple CALL xxxxxxxx suffit.Il est Proche parce que l'adresse en question reste dans la partie code.
Ce n'est peut-être pas le type de lien le plus courrant mais c'est de loin le plus simple. Et comme un exemple vaut tous les discours, allons-y gaiement!!

* Reference To: KERNEL32.ExitProcess, Ord:0075h
:00401201 E8400D0000 Call 00401F46
<-- adresse appartenant à la section code
....
....
* Reference To: KERNEL32.ExitProcess, Ord:0075h
:00401F46 FF2514204000 Jmp dword ptr [00402014]
<-- adresse ayant un rapport avec l'IAT

Dans ce type d'utilisation d'une fonction, on utilise un simple "Call xxxxxxxx" lequel pointe tout en bas de la section .code.
A la fin de la partie .code justement on trouve les différents sauts qui pointent dans l'IAT sur le membre "First Thunk" de la fonction en question
Ici il semble bien qu'on ignore la structure IMAGE_IMPORT_DESCRIPTOR qui est la première normalement consultée. Vous pouvez vous contenter de ces connaissances sans allez plus loin. C'est suffisant.

Vous voulez le détail pour vraiment comprendre...

Avec (ProcDump :
ImageBase = 00400000h
VirtualAddress= 00002000h
RawAddress = 00001400h
0042014 - 00400000 = 0000 2014
Et on prend comme référence non plus le VirtualAdress
mais le RawOffset soit => 0000 1414h (Parce que HexWorkShop se réfère au RawOffset)

dans HexWorkShop en 0000 1414 on trouve le dword F422 0000 (Qui est bien le 'First Thunk" de ExitProcess) car en
F422 0000 au format Intel (inversé donne 0000 22F4)
Et en changeant de base on trouve 0000 22F4 - 0000 2000 + 0000 1400 = 0000 16F4
Et en 0016F4 on trouve bien u.ExitProcess..... (N°Ordinal+Function_Name)

Ca c'est une structure IMAGE_IMPORT_BY_NAME sans le moindre doute. Et Qu'est-ce qui pointe sur une structure IMAGE_IMPORT_BY_NAME ? c'est toujours la structure "FIRST_THUNK" de la fonction en question. On vient donc de prouver que l'adresse ente les crochets pointe belle et bien vers la structure "FIRST_THUNK" de la fonction qu'on Call. (La boucle est bouclée).









II) APPEL DIRECT LOINTAIN :

Celui-ci est sûrement le type le plus courrant de lien entre la partie code et l'IAT.
Je l'appelle ainsi par ce que ce call se sert bien des info contenues dans l'IAT (contrairement aux cas qui vont suivres), mais lointain car cette adresse n'appartient plus à la section code.

* Reference To: KERNEL32.ExitProcess, Ord:0071h
:00401077 FF1554734000 Call dword ptr [00402014]
<-- ayant un rapport direct avec l'IAT.

Ce call là est une concaténation du Call/Jmp dword vu précédemment. Et l'adresse qu'il contient n'est autre que le RVA FirstThunk si vous prenez le soin de lui soustraire l'ImageBase.

Reprenez les données du précédent exemple et vous avez son double. C'est seulement une autre façon de présenter la chose.






III) APPEL INDIRECT :

Je l'appelle indirect parce qu'on ne passe à aucun moment par l'IAT. Ici on se passe de ses services. Malheureusement, c'est le second type de lien le plus courrant.

* Reference To: KERNEL32.ExitProcess, Ord:0071h
:00401077 FF1554734000 Call dword ptr [00407354]
<-- adresse hors du programme.

Ce type d'appel est particulier. Ici le Call ne pointe pas dans l'IAT. Et comme dans le cas précédent ce n'est pas l'adresse entre les crochets[] qui est importante mais ce que contient cette adresse. Ce contenu est lui-même une autre adresse, qui elle pointe directement dans la DLL à l'endroit où se trouve la fonction. On ne passe donc pas par l'IAT, on va chercher la fonction directement dans la DLL.

Exemple complet:

* Reference To: KERNEL32.ExitProcess, Ord:0071h
:00401077 FF1554734000 Call dword ptr [00407354]
(avec par exemple [Contenu_de_00407354] = 833F2FB8)

L'adresse 833F2FB8 n'appartient ni au programme lui-même ni à la DLL (Kernel32.dll) qui contient cette fonction (ExitProcess). On pointe donc à un endroit inconnu mais qui nous renvoie bien vers la fonction en question.

:833F2FB8 push BFF84DF8 <------------------------ adresse de la fonction
:833F2FBD jmp KERNEL32.BFF957CA


Maintenant seulement Ce jmp nous amène à la fonction tant convoitée.

ExitProcess ( )
:BFF84DF8 mov eax, ......
..................
..........

C'est vrai que cet appel n'utilise pas les services de l'IAT, Cependant il n'est pas question pour autant d'altérer le nom de cette fonction dans l'IAT. Car même si le code n'y fait pas appelle, son nom est utilisé à un autre moment pour connaitre toutes les fonctions importées par le programme par exemple en passant par le chemin habituel : IMAGE_IMPORT_DESCRIPTOR => FIRST THUNK => IMAGE_IMPORT_BY_NAME










IV) APPEL INDIRECT RETARDÉ :

Là ça se complique. Le Call appelant la fonction n'utilise plus une adresse fixe mais la valeur contenue dans un Registre. C'est donc une autre mnémonique placée en amont qui doit affecter la valeur correcte au Registre. Un 'Mov', j'ai jamais rien rencontré d'autre pour l'instant, mais un Pop serait possible.

* Reference To: USER32.CreateWindowExA, Ord:0050h
|
:00402719 8B3DC4734000 mov edi, dword ptr [004073C4]
:0040271F 6800000080 push 80000000
:00402724 680000CF00 push 00CF0000
:00402729 6888614000 push 00406188

* Possible StringData Ref from Data Obj ->"Notepad"
|
:0040272E 6820604000 push 00406020
:00402733 6A00 push 00000000
:00402735 FFD7 call edi

En réalité cet appel n'utilise pas non plus l'IAT. C'est une version un poil plus évoluée du type de lien vu précédemment (III). Le registre va pointer sur une adresse n'appartenant ni au programme lui-même ni à la DLL dont on appelle la fonction. Ce registre pointe ailleurs. Mais l'adresse contenue dans le Registre va nous rediriger dans la DLL sur l'entrée de la fonction appelée.

Exemple :

Contenu de [004073C4] vaut 834F8108 donc edi = 834F8108

834F8108 push BFF55C71 <------------------------ adresse de la fonction
834F810D jmp KERNEL32.BFF957CA


Ce saut nous redirige comme tout à l'heure vers l'adresse de la bonne fonction.

CreateWindowExA ( )
:BFF55C71 mov ch, 30
..........



Les Registres utilisés sont principalement EDI et ESI, mais on trouve aussi EBX parfois. Pour ce qui est des Push précédant l'appel de la fonction je pense que vous avez devinez ce qu'ils représentent. Donc j'en dirais pas plus... Bon d'accord, mais juste un indice alors... J'ai pas tout mis ici, mais il y a encore sept autres Push au dessus de cette partie de code, ce qui en fait douze au total au dessus de l'appel à la fonction CreateWindowEx. Voyez plutôt la référence W32API et le nombre d'arguments de cette fonction justement.










V) RETABLIR LES LIENS ENTRE LE CODE ET LES FONCTIONS :

Revenons au principal problème.

Quel est le but de tout ceci.... Imaginons.... Je souhaite ajouter une DLL et ses fonctions dans un programme. Pire je souhaite utiliser une fonction (non présente) dans une DLL qui elle est déjà déclarée. Dans les deux cas je suis obligé de reconstruire un nouvel IAT, Déplacer des fonctions pour pouvoir en insérer certaines autres entre elles. Résultat, les adresses initiales où elles étaient ne sont plus valides.

Maintenant supposons que nous ayons réussit à recréer un IAT valide avec en plus nos rajouts, et ça, ça n'a rien d'impossible en fait, j'ai même automatisé cette étape grâce un un petit programme. Il faut maintenant intervenir dans la section .code elle-même car beaucoup d'appels ne sont plus correctement adressés.
C'est facile de rediriger les deux premiers types de liens, il suffit de placer le nouveau "First Thunk" au niveau du "jmp" des fonctions importées.

Par contre pour les deux derniers types de liens, ça devient chaud. Le point crussial c'est qu'ils sont indirect, il faud lire le contenu de leurs adresses. Ca signifie qu'il faut que le programme soit lancé. Par contre je me suis aperçu que toutes ces adresses contiennent déjà les bonnes valeurs même si on est toujours sur L'EP.
On peut donc imaginer que le programme qui devra résoudre les liens se serve des Debug API (en particulier CreateProcess) pour pouvoir le charger en mémoire mais sans l'exécuté, on resterait sans bouger sur l'EP. Le point fort, c'est qu'en faisant ça on charge le programme en mémoire ainsi que les éléments externes qu'il utilise lui-même. On pourrait alors rechercher les FF15.... Call dword ptr [xxxxxxxx] et cette fois-ci lire le contenu du xxxxxxxx. Il est donc possible de retrouver les fonctions, et ainsi remplacer ce type de Call par des Call direct. Mais bon, c'est bien chaud.... ça demande de vraiment s'inverstir et d'avoir du temps devant soit.

J'avais fait un programme qui réussissait à résoudre ces 4 types de liens. Mais y en a d'autres plus subtiles encore, et donc au final c'était l'échèc. Donc pour ma part, et ça ne concerne que moi, il me sembme que retoucher l'IAT n'est pas une bonne méthode, d'autant plus que certains chemins détournés peuvent se révélés plus habiles.



Par Morgatte